package com.pxst.utils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.pxst.annotations.mybatits.Query;
import com.pxst.constants.MyBatitsQueryConstants;

/**
 * 
 * 
 * @author yangxy
 * @version 创建时间：2023年7月27日 上午11:37:53
 */
public class BuildQueryUtils {
	/**
	 * 查询条件构造方法
	* @author yangxy
	* @version 创建时间：2023年8月15日 下午3:23:42 
	* @param <P> 查询条件对象
	* @param <T> 数据库对应实体
	* @param clz
	* @param p
	* @return
	 */
	public static <P, T> QueryWrapper<T> build(Class<T> clz, P p) {
		QueryWrapper<T> query = new QueryWrapper<T>();
		Field[] fields = p.getClass().getDeclaredFields();
		try {
			for (Field field : fields) {
				field.setAccessible(true);
				Object object = field.get(p);
				if (ObjectUtils.isEmpty(object)) {
					continue;
				}
				Query annotation = field.getAnnotation(Query.class);
				if (ObjectUtils.isEmpty(annotation)) {
					continue;
				}
				String operate = annotation.operate();
				String dbFiled = annotation.dbFiled();
				if (StringUtils.isEmpty(dbFiled)) {
					dbFiled = field.getName();
				}
				String type = annotation.type();

				//			String firstCharUpper = field.getName().substring(0, 1).toUpperCase();
				//            String invokeMethodName = "get" + firstCharUpper + field.getName().substring(1);
				//            Property<T, invokeMethodName> colum = new Property<T, invokeMethodName>();
				if (operate.equals(MyBatitsQueryConstants.AND)) {
					switch (type) {
					case MyBatitsQueryConstants.GT:
						query.gt(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.GTE:
						query.ge(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.LT:
						query.lt(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.LTE:
						query.le(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.EQ:
						query.eq(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.NOT_EQ:
						query.ne(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.IN:
						Type genericType = field.getGenericType();
						ParameterizedType pt = (ParameterizedType) genericType;
						Class<?> actualTypeArgument = (Class<?>) pt.getActualTypeArguments()[0];
						List<?> parseArray = JSONArray.parseArray(JSON.toJSONString(object), actualTypeArgument);
						query.in(changeStr(dbFiled), parseArray);
						break;
					case MyBatitsQueryConstants.NOT_IN:
						Type genericType1 = field.getGenericType();
						ParameterizedType pt1 = (ParameterizedType) genericType1;
						Class<?> actualTypeArgument1 = (Class<?>) pt1.getActualTypeArguments()[0];
						List<?> parseArray1 = JSONArray.parseArray(JSON.toJSONString(object), actualTypeArgument1);
						query.notIn(changeStr(dbFiled), parseArray1);
						break;
					case MyBatitsQueryConstants.LIKE:
						query.like(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.NOT_LIKE:
						query.notLike(changeStr(dbFiled), object);
						break;
					}
				} else if (operate.equals(MyBatitsQueryConstants.OR)) {
					switch (type) {
					case MyBatitsQueryConstants.GT:
						query.or().gt(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.GTE:
						query.or().ge(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.LT:
						query.or().lt(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.LTE:
						query.or().le(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.EQ:
						query.or().eq(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.NOT_EQ:
						query.or().ne(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.IN:
						Type genericType = field.getGenericType();
						ParameterizedType pt = (ParameterizedType) genericType;
						Class<?> actualTypeArgument = (Class<?>) pt.getActualTypeArguments()[0];
						List<?> parseArray = JSONArray.parseArray(JSON.toJSONString(object), actualTypeArgument);
						query.or().in(changeStr(dbFiled), parseArray);
						break;
					case MyBatitsQueryConstants.NOT_IN:
						Type genericType1 = field.getGenericType();
						ParameterizedType pt1 = (ParameterizedType) genericType1;
						Class<?> actualTypeArgument1 = (Class<?>) pt1.getActualTypeArguments()[0];
						List<?> parseArray1 = JSONArray.parseArray(JSON.toJSONString(object), actualTypeArgument1);
						query.or().notIn(changeStr(dbFiled), parseArray1);
						break;
					case MyBatitsQueryConstants.LIKE:
						query.or().like(changeStr(dbFiled), object);
						break;
					case MyBatitsQueryConstants.NOT_LIKE:
						query.or().notLike(changeStr(dbFiled), object);
						break;
					}
				}
			} 
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e.getMessage());
		}
		return query;
	}

	/**
	 * 驼峰字符串转换为待下划线字符串
	 * 
	 * @author yangxy
	 * @version 创建时间：2023年7月27日 下午2:16:42
	 * @param fieldName
	 * @return
	 */
	private static String changeStr(String fieldName) {
		StringBuffer sb = new StringBuffer("");
		for (int i = 0; i < fieldName.length(); i++) {
			char c = fieldName.charAt(i);
			if (Character.isUpperCase(c)) {
				sb.append("_").append(c);
			} else {
				sb.append(c);
			}
		}
		return sb.toString().toLowerCase();
	}
}
